/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2010 huliqing, huliqing.cn@gmail.com
 *
 * This file is part of QFaces.
 * QFaces is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * QFaces is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with QFaces.  If not, see <http://www.gnu.org/licenses/>.
 *
 * 这个文件是QFaces的一部分。
 * 您可以单独使用或分发这个文件，但请不要移除这个头部声明信息.
 * QFaces是一个自由软件，您可以自由分发、修改其中的源代码或者重新发布它，
 * 新的任何修改后的重新发布版必须同样在遵守LGPL3或更后续的版本协议下发布.
 * 关于LGPL协议的细则请参考COPYING、COPYING.LESSER文件，
 * 您可以在QFaces的相关目录中获得LGPL协议的副本，
 * 如果没有找到，请连接到 http://www.gnu.org/licenses/ 查看并获取副本。
 *
 * - Author: Huliqing
 * - Contact: huliqing.cn@gmail.com
 * - License: GNU Lesser General Public License (LGPL)
 * - Blog and source code availability: http://www.huliqing.name/
 */

package name.huliqing.qfaces.render;

import java.io.IOException;
import java.util.logging.Logger;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;
import name.huliqing.qfaces.QFaces;
import name.huliqing.qfaces.component.DynFrame;
import name.huliqing.qfaces.component.Frame;

public class DynFrameRenderer extends Renderer{
	private final static Logger logger = Logger.getLogger(DynFrameRenderer.class.getName());
	
	// 后缀For visible state input hidden object id.
	// 记客户端能够记住窗口的当前打开状态
	// 这要求DynFrame必须放在某一个Form组件之内
	private final static String VISIBLE_STATE_SUFFIX_ID = ":visibleState";
	
	// 客户端组件ID后缀，目标组件用于记住Frame中客户端中的位置
	private final static String CLIENT_POSITION_SUFFIX_ID = ":position";
	
	@Override
    public void encodeBegin(FacesContext fc,  UIComponent ui) throws IOException {
		super.encodeBegin(fc, ui);
		DynFrame df = (DynFrame) ui;
		QFaces.getResLoader2().loadJavaScript(df, "DynFrame.js");
		
		if (df.getCenter() == null)
			df.setCenter(Boolean.FALSE);
		
		if (df.getShade() == null)
			df.setShade(Boolean.FALSE);
		
		if (df.getShadeColor() == null)
			df.setShadeColor("black");
		
		if (df.getShadeOpaque() == null)
			df.setShadeOpaque(.5f);
		
		if (df.getOnOpen() == null)
			df.setOnOpen("");
		
		if (df.getOnClose() == null)
			df.setOnClose("");
		
		if (df.getFrame() == null) {
			df.setFrame(new Frame());
			df.getFrame().loadAttributeFrom(df);
			// -1表示未设置Frame在中客户端中的位置
			if (df.getFrame().getClientX() == null)
				df.getFrame().setClientX(-1);
			if (df.getFrame().getClientY() == null)
				df.getFrame().setClientY(-1);
		}
		
		// Check data
		if (df.getShadeOpaque().floatValue() > 1.0f || df.getShadeOpaque() < .0f) {
			logger.warning("The value of attribute \"ShadeOpaque\" must between [0.0, 1.0]");
			df.setShadeOpaque(0.5f);
		}
		
		// 渲染输出
		df.getFrame().encodeBegin(fc);
    }

    @Override
    public void encodeEnd(FacesContext fc, UIComponent ui) throws IOException {
    	super.encodeEnd(fc, ui);
    	DynFrame df = (DynFrame) ui;
    	ResponseWriter rw = fc.getResponseWriter();
    	
    	// 渲染hidden 用于保存组件在客户端的可视状态, 1为可见，0为不可见
    	String vid = df.getClientId(fc) + VISIBLE_STATE_SUFFIX_ID;
    	rw.startElement("input", df);
    	rw.writeAttribute("id", vid, "id");
    	rw.writeAttribute("name", vid, "name");
    	rw.writeAttribute("type", "hidden", "type");
    	rw.writeAttribute("value", (df.getFrame().getVisible() ? "1" : "0"), "value");
    	rw.endElement("input");
    	
    	// 渲染hidden 用于记住客户端组件的目标位置,格式为 "x,y"
    	String pid = df.getClientId(fc) + CLIENT_POSITION_SUFFIX_ID;
    	rw.startElement("input", df);
    	rw.writeAttribute("id", pid, "id");
    	rw.writeAttribute("name", pid, "name");
    	rw.writeAttribute("type", "hidden", "type");
    	rw.writeAttribute("value", (df.getFrame().getClientX() + "," + df.getFrame().getClientY()), "value");
    	rw.endElement("input");
    	
    	// End render
    	df.getFrame().encodeEnd(fc);
    	
        StringBuilder jsInit = new StringBuilder("Q.F.UIDynFrame.init(")
        	.append(" \"" + df.getClientId(fc) + "\"")
        	.append(",\"" + vid + "\"")
        	.append(",\"" + pid + "\"")
        	.append(",\"" + df.getFrame().getFrameId() + "\"")
        	.append(",\"" + df.getFrame().getHeaderId() + "\"")
        	.append(",\"" + df.getFrame().getCloseId() + "\"")
        	.append(",\"" + df.getFrame().getRenderBorder() + "\"")
        	.append(",\"" + df.getFrame().getRenderCloseButton() + "\"")
        	.append(",\"" + df.getFrame().getDrag() + "\"")        	
        	.append(",\"" + df.getCenter() + "\"")
        	.append(",\"" + df.getShade() + "\"")
        	.append(",\"" + df.getShadeColor() + "\"")
        	.append(",\"" + df.getShadeOpaque() + "\"")
        	.append(",\"" + df.getOnOpen() + "\"")
        	.append(",\"" + df.getOnClose() + "\"")
        	.append(")");
        QFaces.getResLoader2().loadJavaScriptInit(df, jsInit.toString());
    }

    // -----------------------------------------------------------------
    @Override
    public void decode(FacesContext fc, UIComponent ui) {
    	super.decode(fc, ui);
    	DynFrame df = (DynFrame) ui;
    	// 让组件知道来自客户端的当前可见状态，这样在重新渲染时可同步这个状态
    	String hid = df.getClientId(fc) + VISIBLE_STATE_SUFFIX_ID;
    	String vState = QFaces.getParam(hid);
    	if (vState != null) { // 这个判断是必要的
    		df.getFrame().setVisible("1".equals(vState));
    	}
    	// 获取组件在客户端中的位置
    	String pid = df.getClientId(fc) + CLIENT_POSITION_SUFFIX_ID;
    	String pState = QFaces.getParam(pid);
    	if (pState != null) {
    		if (pState.indexOf(",") != -1) {
    			String[] ps = pState.split(",");
    			Float clientX = QFaces.convertToFloat(ps[0]);
    			Float clientY = QFaces.convertToFloat(ps[1]);
    			df.getFrame().setClientX(clientX != null ? clientX.intValue() : -1);
    			df.getFrame().setClientY(clientY != null ? clientY.intValue() : -1);
    		} else {
    			logger.warning("Position state format error, \",\" not found!");    			
    		}
    	}
    }
}
